using System;
using System.Reflection;
using Autofac;
using ECommon.Configurations;
using ECommon.Serilog;
using ENode.Configurations;
using ENodeMicro.Common;
using ENodeMicro.GRPC;
using ENodeMicro.QueryServices.EFCore;
using ENodeMicro.WebAPI.Extensions;
using ENodeMicro.WebAPI.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using NConsul.AspNetCore;
using HealthCheckService = ENodeMicro.WebAPI.Services.HealthCheckService;

namespace ENodeMicro.WebAPI
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            ConfigSettings.BusinessConnectionString = Configuration.GetConnectionString("business");
            ConfigSettings.ENodeConnectionString = Configuration.GetConnectionString("enode");
            ConfigSettings.Initialize();

            var connectionString = "data source=127.0.0.1;database=member_data; uid=root;pwd=1234567;charset=utf8mb4;";
            services.AddDbContext<MemberDbContext>(opt =>
                opt.UseMySql(connectionString, p => p.MigrationsAssembly("ENodeMicro.WebAPI")));

            services.AddControllers();

            #region Swagger Config
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo
                {
                    Version = "v1",
                    Title = "Member Module API",
                    Description = "Member Module API",
                    Contact = new OpenApiContact
                    {
                        Name = "Van Zheng",
                        Email = "zheng_jinfan@126.com",
                        Url = new Uri("https://vanz-blogs.github.io/"),
                    }
                });
            });
            #endregion


            #region GRPC Config
            services.AddGrpc();
            // 注册到Consul
            var host = ConfigSettings.LocalIpv4.ToString();
            var gRpcPort = ConfigSettings.GRpcPort;
            var httpPort = ConfigSettings.HttpPort;
            const string httpServiceName = "MemberModuleHttpService";
            const string gRpcServiceName = "MemberModuleGRpcService";
            // 注册gRpc服务
            services.AddConsul(ConfigSettings.ConsulAddress)
                .AddGRPCHealthCheck($"{host}:{gRpcPort}")
                .RegisterService(gRpcServiceName, host, gRpcPort, new[]
                {
                    "gRpc"
                });
            // 注册http服务
            services.AddConsul(ConfigSettings.ConsulAddress)
                .AddHttpHealthCheck($"http://{host}:{httpPort}/health_check")
                .RegisterService(httpServiceName, host, httpPort, new[]
                {
                    $"urlprefix-/{httpServiceName}" // urlprefix-/ 用于适配Fabio
                });
            #endregion
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            // Enable middleware to serve generated Swagger as a JSON endpoint.
            app.UseSwagger();
            // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
            // specifying the Swagger JSON endpoint.
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
            });
            // app.UseHttpsRedirection();
            app.UseRouting();
            // app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                #region GRPC service config
                endpoints.MapGrpcService<MemberService>();
                endpoints.MapGrpcService<HealthCheckService>();
                #endregion

                endpoints.MapControllers();
            });

            var assemblies = new[]
            {
                Assembly.Load("ENodeMicro.Common"),
                Assembly.Load("ENodeMicro.Commands"),
                Assembly.Load("ENodeMicro.QueryServices"),
                Assembly.Load("ENodeMicro.QueryServices.EFCore"),
                Assembly.Load("ENodeMicro.WebAPI")
            };
            ENodeConfiguration
                .Instance
                .InitializeBusinessAssemblies(assemblies)
                .StartEQueue();

        }


        public void ConfigureContainer(ContainerBuilder builder)
        {
            InitializeENode(builder);
        }

        private void InitializeENode(ContainerBuilder builder)
        {
            var assemblies = new[]
            {
                Assembly.Load("ENodeMicro.Common"),
                Assembly.Load("ENodeMicro.Commands"),
                Assembly.Load("ENodeMicro.QueryServices"),
                Assembly.Load("ENodeMicro.QueryServices.EFCore"),
                Assembly.Load("ENodeMicro.WebAPI")
            };
            var loggerFactory = new SerilogLoggerFactory()
                .AddFileLogger("ECommon", "logs\\ecommon")
                .AddFileLogger("EQueue", "logs\\equeue")
                .AddFileLogger("ENode", "logs\\enode", minimumLevel: Serilog.Events.LogEventLevel.Debug);

            ECommon.Configurations.Configuration
                .Create()
                .UseAutofac(builder)
                .RegisterCommonComponents()
                .UseSerilog(loggerFactory)
                .UseJsonNet()
                .RegisterUnhandledExceptionHandler()
                .CreateENode()
                .RegisterENodeComponents()
                .RegisterBusinessComponents(assemblies)
                .UseEQueue();
        }
    }
}